package com.authsphere.security.listener.authentication.failure.credential;

import com.authsphere.security.account.api.lock.AccountLockedEnum;
import com.authsphere.security.account.api.lock.AccountLockoutService;
import com.authsphere.security.account.api.lock.LockedAccount;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.core.Authentication;

/**
 * @program: AuthSphere
 * @description: SpringSecurity  内置的 AuthenticationFailureBadCredentialsEvent 监听器
 * @see org.springframework.security.authentication.ProviderManager#eventPublisher
 * @see org.springframework.security.authentication.DefaultAuthenticationEventPublisher
 * @author: YuKai Fan
 * @create: 2025/3/13 20:44
 **/
public class BadCredentialsApplicationListener implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {

    private final AccountLockoutService accountLockoutService;

    public BadCredentialsApplicationListener(AccountLockoutService accountLockoutService) {
        this.accountLockoutService = accountLockoutService;
    }

    @Override
    public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
        Authentication authentication = event.getAuthentication();
        LockedAccount lockout = accountLockoutService.lockout(authentication.getName());
        if (lockout == null) {
            // do nothing
            return;
        }
        int restAttempts = lockout.getRestAttempts();
        int lockMinutes = lockout.getLockMinutes();
        String message = "Bad Credentials";
        if (restAttempts > 0) {
            message = String.format(AccountLockedEnum.BAD_CREDENTIALS_RETRY.getMessage(), restAttempts);
        }
        if (restAttempts == 0) {
            message = String.format(AccountLockedEnum.LOCKED_ACCOUNT.getMessage(), lockMinutes);
        }
        if (lockout.isLockedPermanently()) {
            message = AccountLockedEnum.BAD_CREDENTIALS_RETRY.getMessage();
        }
        throw new BadCredentialsException(message);
    }
}
